package syncer

import (
	"fmt"
	"github.com/aliyun/aliyun-oss-go-sdk/oss"
	"github.com/xiyoufang/cloud-syncer/internal/log"
	"os"
)

type OssSyncer struct {
	client *oss.Client
	bucket *oss.Bucket
	logger *log.Logger
}

func NewOssSyncer(accessKeyId, secretAccessKey, bucketName, endpoint string, logger *log.Logger) (Syncer, error) {
	client, err := oss.New(endpoint, accessKeyId, secretAccessKey)
	if err != nil {
		return nil, err
	}
	bucket, err := client.Bucket(bucketName)
	if err != nil {
		return nil, err
	}
	return &OssSyncer{
		client: client,
		bucket: bucket,
		logger: logger,
	}, nil
}

func (s *OssSyncer) PushFile(local string, remote string) error {
	err := s.bucket.PutObjectFromFile(remote, local) // 文件最大不能超过5GB
	return err
}

// 分片上传函数
func (s *OssSyncer) uploadMultipart(bucket *oss.Bucket, objectName, localFilename string) error {
	partSize := int64(5 * 1024 * 1024)
	// 将本地文件分片
	chunks, err := oss.SplitFileByPartSize(localFilename, partSize)
	if err != nil {
		return fmt.Errorf("failed to split file into chunks: %w", err)
	}

	// 打开本地文件。
	file, err := os.Open(localFilename)
	if err != nil {
		return fmt.Errorf("failed to open file: %w", err)
	}
	defer func() {
		_ = file.Close()
	}()

	// 步骤1：初始化一个分片上传事件。
	imur, err := bucket.InitiateMultipartUpload(objectName)
	if err != nil {
		return fmt.Errorf("failed to initiate multipart upload: %w", err)
	}

	// 步骤2：上传分片。
	var parts []oss.UploadPart
	for _, chunk := range chunks {
		part, err := bucket.UploadPart(imur, file, chunk.Size, chunk.Number)
		if err != nil {
			// 如果上传某个部分失败，尝试取消整个上传任务。
			if abortErr := bucket.AbortMultipartUpload(imur); abortErr != nil {
				s.logger.Error("Failed to abort multipart upload: %v", abortErr)
			}
			return fmt.Errorf("failed to upload part: %w", err)
		}
		parts = append(parts, part)
	}

	// 步骤3：完成分片上传。
	_, err = bucket.CompleteMultipartUpload(imur, parts)
	if err != nil {
		// 如果完成上传失败，尝试取消上传。
		if abortErr := bucket.AbortMultipartUpload(imur); abortErr != nil {
			s.logger.Error("Failed to abort multipart upload: %v", abortErr)
		}
		return fmt.Errorf("failed to complete multipart upload: %w", err)
	}
	s.logger.Info("Multipart upload completed successfully.")
	return nil
}
